#include "EventManager.h"
static std::tr1::shared_ptr<EventManager> g_Manager;

EventManager::EventManager() : m_ActiveQueue(0)
{
	RE_Logger::GetGlobalLogger()->WriteLog("Initializing the event manager.");
	RegisterGeneralPurposeEvents();
}
EventManager::~EventManager()
{
	
}
void EventManager::VQueEvent(EventDataPtr eventData)
{
	std::list<EventDataPtr> * activeQueue = &m_EventQueueList[m_ActiveQueue];
	if(!VValidateEventType(eventData->VGetEventType()))
	{
		assert(0 && "Attempt to add invalid event type to the queue");
	}
	//TODO: ADD EVENT REGISTER CODE AND CHECKS
	
	activeQueue->push_back(eventData);
}

void EventManager::VTriggerEvent(EventDataPtr eventData)
{
#ifdef CFG_DEBUGLOG
	RE_Logger::GetGlobalLogger()->Log("EventManager: Triggering Event of Type: ");
	RE_Logger::GetGlobalLogger()->Log(eventData->VGetEventType().c_str());
	RE_Logger::GetGlobalLogger()->WriteLog("");
#endif
	//loop through all listeners and find out which of them has subscribed for this event type
	const EventType * eventType = &eventData->VGetEventType();
	if(!VValidateEventType(*eventType))
	{
#ifdef CFG_DEBUGLOG
		RE_Logger::GetGlobalLogger()->WriteLog("Invalid event type.");
#endif
		return;
	}
	EventListenerMap::iterator iter = m_EventListenerMap.find(*eventType);
	if(iter == m_EventListenerMap.end())
	{
		//check global events
		EventListenerList::iterator i = m_GlobalListeners.begin();
		while( i != m_GlobalListeners.end())
		{
			(*i)->HandleEvent(eventData);
			++i;
		}
		return;
	}
	EventListenerList * listeners = &iter->second;
	for(auto iter_list = listeners->begin(); iter_list != listeners->end(); iter_list++)
	{
		(*iter_list)->HandleEvent(eventData);
	}
}

void EventManager::VTick()
{
	std::list<EventDataPtr> * activeQueue = &m_EventQueueList[m_ActiveQueue];
	//now make the other queue active
	m_ActiveQueue = !m_ActiveQueue;

	if(activeQueue->size() > 0)
	{
		std::list<EventDataPtr>::iterator i = activeQueue->begin();
		while(i != activeQueue->end())
		{
			VTriggerEvent(*i);
			++i;
		}

		activeQueue->clear();
	}
}


void EventManager::VRemoveLastEventFromQueue()
{
	m_EventQueueList[m_ActiveQueue].pop_back();

}
void EventManager::VAddListener(EventListenerPtr listener, EventType evt_type)
{
	//check if this evt type is already registered
	if(!VValidateEventType(evt_type))
	{
		return;
	}
	//now find the event in the listener map
	EventListenerMap::iterator iter_listener = m_EventListenerMap.find(evt_type);
	if(iter_listener == m_EventListenerMap.end())
	{
		// no listener for this type, create a pair so we can push the listeners
		m_EventListenerMap.insert( std::make_pair( evt_type, EventListenerList()) );

		iter_listener =  m_EventListenerMap.find(evt_type);
	}
	//check if this listener is not already added
	if(iter_listener->second.size() > 0)
	{
		EventListenerList::iterator iter_list = iter_listener->second.begin();
		while(iter_list != iter_listener->second.end())
		{
			if( *iter_list == listener )
			{
				assert(0 && "Attempt to add the same listener twice.");
				return;
			}
			++iter_list;
		}
	}
	//now inser the listener
	iter_listener->second.push_back(listener);
}


void EventManager::VAddListener(EventListenerPtr listener)
{
	EventListenerMap::iterator i = m_EventListenerMap.begin();
	while(i != m_EventListenerMap.end())
	{
		EventListenerList::iterator u = (*i).second.begin();
		while(u != (*i).second.end())
		{
			if((*u) == listener)
			{
				return;
			}
			++u;
		}
		++i;
	}
	//now check if it is not already in the global list;
	EventListenerList::iterator o = m_GlobalListeners.begin();
	while(o != m_GlobalListeners.end())
	{
		if((*o) == listener)
		{
			return;
		}
		++o;
	}
	m_GlobalListeners.push_back(listener);
}

void EventManager::RegisterGeneralPurposeEvents()
{
	RE_Logger::GetGlobalLogger()->WriteLog("Registering General Purpose Engine Events");
	VRegisterEventType(EventData_NewActor::m_EventType); // New actor
	VRegisterEventType(EventData_NewActorComponent::m_EventType); // RE_NEW actor component
	VRegisterEventType(EventData_ActorComponentModified::m_EventType);
	VRegisterEventType(EventData_ActorModified::m_EventType);
	VRegisterEventType(EventData_ActorDestroyed::m_EventType);
	VRegisterEventType(EventData_ActorComponentDestroyed::m_EventType);

	VRegisterEventType(EventData_Input_KeyDown::m_EventType); // key down
	VRegisterEventType(EventData_Input_KeyUp::m_EventType); // key up
	VRegisterEventType(EventData_Input_MouseMove::m_EventType); // mouse move

	VRegisterEventType(EventData_GameStart::m_EventType);
	VRegisterEventType(EventData_GameEnd::m_EventType);
	VRegisterEventType(EventData_View_MoveForward::m_EventType);
	VRegisterEventType(EventData_View_MoveLeft::m_EventType);
	VRegisterEventType(EventData_View_Rotate::m_EventType);
}

bool EventManager::VValidateEventType(const EventType & evt)
{
	EventTypeList::iterator i = m_EventTypeList.begin();
	while(i != m_EventTypeList.end())
	{
		if((*i) == evt)
		{
			return true;
		}
		++i;
	}
	return false;
}

bool EventManager::VRegisterEventType(EventType evt_type)
{
	if(!VValidateEventType(evt_type))
	{
		m_EventTypeList.push_back(evt_type);
		return true;
	}
	return false;
}
void EventManager::VRemoveListener(EventListenerPtr listener, EventType evt_type)
{
	//test function for now. Need real impl
	EventListenerMap::iterator i = m_EventListenerMap.find(evt_type);
	i->second.remove(listener);

}
void EventManager::VRemoveListener(EventListenerPtr listener)
{
}

EventManager * const EventManager::Get()
{
	if(g_Manager == std::tr1::shared_ptr<EventManager>())
	{
		g_Manager = std::tr1::shared_ptr<EventManager>(RE_NEW EventManager);
	}
	return g_Manager.get();
}
void EventManager::Release()
{
	g_Manager = std::tr1::shared_ptr<EventManager>();
}

